package br.com.saber.certificacao.modelos.relacionamentos;

import br.com.saber.certificacao.enums.TipoQuestao;
import br.com.saber.certificacao.modelos.Prova;
import br.com.saber.certificacao.modelos.Questao;
import br.com.saber.certificacao.modelos.Resposta;
import br.com.saber.certificacao.modelos.relacionamentos.idcompostos.IdProvaQuestaoPk;
import br.com.saber.certificacao.modelos.validadores.interfaces.ValidadoInterface;
import java.util.Set;
import java.util.TreeSet;
import javax.persistence.*;

/**
 *  Calsse que representa cada questão que cai na prova.
 *  A medida que o aluno vai respondendo a prova as respostas de cada questão são armazenadas nesta classe e gravadas no banco.
 * @author gbvbahia
 */
@Entity
@Table(name = "prova_questao")
public class ProvaQuestao implements ValidadoInterface, Comparable<ProvaQuestao> {

    @EmbeddedId
    private IdProvaQuestaoPk id = new IdProvaQuestaoPk();

    @ManyToOne(targetEntity = br.com.saber.certificacao.modelos.Prova.class, fetch = FetchType.EAGER)
    @JoinColumn(name = "prova_id", referencedColumnName = "id", insertable = false, updatable = false)
    private Prova prova;

    @ManyToOne(targetEntity = br.com.saber.certificacao.modelos.Questao.class, fetch = FetchType.EAGER)
    @JoinColumn(name = "questao_id", referencedColumnName = "id", insertable = false, updatable = false)
    private Questao questao;

    @Column(name = "numero_questao", nullable = false, unique = false)
    private Integer numeroQuestao;

    @Column(name = "resposta_marcada", nullable = false, unique = false)
    private boolean respondida;

    /**
     * São as respostas marcadas para esta questão
     * Cada questão participa individualmente neste relacionamento
     * não havendo perigo de misturar as respostas com outras questões
     */
    @ManyToMany(targetEntity = br.com.saber.certificacao.modelos.Resposta.class, fetch = FetchType.EAGER)
    @JoinTable(name = "respostas_marcadas_na_prova",
    joinColumns = {
        @JoinColumn(name = "prova_id", referencedColumnName = "prova_id"),
        @JoinColumn(name = "questao_id", referencedColumnName = "questao_id")},
    inverseJoinColumns =
    @JoinColumn(name = "resposta_id", referencedColumnName = "id"))
    private Set<Resposta> respostasMarcadasNaProva;

    public ProvaQuestao() {
    }

    public ProvaQuestao(Prova prova, Questao questao, Integer numeroQuestao) {
        this.prova = prova;
        this.questao = questao;
        this.numeroQuestao = numeroQuestao;
        this.respondida = false;
        this.id = new IdProvaQuestaoPk(prova.getId(), questao.getId());
    }

    /**
     * Adicione resposta marcada para a questão corrente.
     * Se a questão for única escolha limpa o Set para garantir 
     * uma única questão ao adicionar.
     * Se deseja adicionar uma coleção removando os que não estão
     * dentro da mesma, utilize setRespostasMarcadasNaProva.
     * @see setRespostasMarcadasNaProva(Set respostasMarcadasNaProva)
     * @param resposta 
     */
    public void addRespostaMarcada(Resposta resposta) {
        if (this.questao.getTipoQuestao().equals(TipoQuestao.UNICA_ESCOLHA)) {
            this.respostasMarcadasNaProva = new TreeSet<Resposta>();
        }
        getRespostasMarcadasNaProva().add(resposta);
        this.respondida = getRespostasMarcadasNaProva().isEmpty() ? false : true;
    }

    /**
     * fetch=FetchType.EAGER
     * Representa todas as respostas que foram marcadas para esta questão da prova.
     * @return Um set com todas as questões marcadas.
     */
    public Set<Resposta> getRespostasMarcadasNaProva() {
        if (respostasMarcadasNaProva == null) {
            respostasMarcadasNaProva = new TreeSet<Resposta>();
        }
        return respostasMarcadasNaProva;
    }

    /**
     * fetch=FetchType.EAGER
     * Representa todas as respostas que foram marcadas para esta questão da prova.
     * @param respostasMarcadasNaProva
     */
    public void setRespostasMarcadasNaProva(Set<Resposta> respostasMarcadasNaProva) {
        if (respostasMarcadasNaProva == null || respostasMarcadasNaProva.isEmpty()) {
            this.respondida = false;
        } else {
            this.respondida = true;
        }
        this.respostasMarcadasNaProva = respostasMarcadasNaProva;
    }

    public Integer getNumeroQuestao() {
        return numeroQuestao;
    }

    public void setNumeroQuestao(Integer numeroQuestao) {
        this.numeroQuestao = numeroQuestao;
    }

    public boolean isRespondida() {
        return respondida;
    }

    public IdProvaQuestaoPk getId() {
        return id;
    }

    public void setId(IdProvaQuestaoPk id) {
        this.id = id;
    }

    public Prova getProva() {
        return prova;
    }

    public void setProva(Prova prova) {
        this.prova = prova;
    }

    public Questao getQuestao() {
        return questao;
    }

    public void setQuestao(Questao questao) {
        this.questao = questao;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final ProvaQuestao other = (ProvaQuestao) obj;
        if (this.prova != other.prova && (this.prova == null || !this.prova.equals(other.prova))) {
            return false;
        }
        if (this.questao != other.questao && (this.questao == null || !this.questao.equals(other.questao))) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 79 * hash + (this.prova != null ? this.prova.hashCode() : 0);
        return hash;
    }

    @Override
    public int compareTo(ProvaQuestao o) {
        int toReturn = 0;
        if (toReturn == 0) {
            toReturn = this.numeroQuestao.compareTo(o.getNumeroQuestao());
        }
        if (toReturn == 0) {
            prova.compareTo(o.getProva());
        }
        if (toReturn == 0) {
            toReturn = questao.compareTo(o.getQuestao());
        }
        if (toReturn == 0) {
            toReturn = this.id.compareTo(o.getId());
        }
        return toReturn;
    }
}
